\documentclass[a4paper,10pt]{article}
\usepackage[utf8x]{inputenc}

%opening
\title{Trabajo Pr\'actico \#0}
\author{Diego Sisto, Emiliano Ritiro, Marcelo Suvia}

\begin{document}

\maketitle
\begin{center}
\begin{tabular}{ | l | c | }
  \hline
  Diego Sisto & 84823 \\
  \hline
  Emiliano Ritiro & 86768 \\
  \hline
  Marcelo Suvia & 82493 \\
  \hline
\end{tabular}
\end{center}

\newpage

\renewcommand{\contentsname}{Contenido}
\tableofcontents

\newpage

\section{Introducci\'on}
\paragraph{}
Este trabajo pr\'actico tiene el fin de familiarizar a los estudiantes con las herramientas a utilizar en el curso.
Las herramientas son:
\begin{itemize}
 \item Lenguaje de programación C
 \item GNU Compiler Collection (GCC)
 \item GXemul, emulador de la arquitectura MIPS
 \item UNIX b\'asico (comandos del shell, SSH)
 \item \LaTeX , herramienta de documentaci\'on
\end{itemize}

\section{Fechas}
\begin{itemize}
  \item Entrega: 23/3/2010
  \item \'Ultima revisi\'on: 30/3/2010
  \item Vencimiento: 6/4/2010
\end{itemize}


\newpage
\section{Documentaci\'on}
\subsection{Programa}
\paragraph{}
El programa es una utilidad para realizar volcados hexadecimales de archivos binarios.
Asimismo puede hacer el proceso inverso y convertir archivos hexadecimales a archivos binarios.
\subsection{Diseño}
\paragraph{}
Para resolver el trabajo practico se decidio descomponer el problema en dos funciones principales sobre las que se basa la solucion:
\begin{itemize}
\item void hexToBin(...) y void binToHex(...):
Estas funciones procesan los datos de entrada y los escriben en el flujo de salida definido como parametro en las funciones.\item char* leerLinea() :
Lee una linea de la entrada estandar.
\item void process(...), void inverseProcess (...), etc:
Funciones de soporte para la conversion de datos.
\end{itemize}

\subsection{Compatibilidad}
El sistema fue desarrollado y probado exitosamente para las siguientes plataformas:
\begin{itemize}
  \item Ubuntu 9.10
  \item Kubuntu 7.04
  \item Plataforma BSD - MIPS suministrada por la pr\'actica.
\end{itemize}

\subsection{Tests}
\paragraph{}
El programa viene acompa\~nado de una serie de tests para verificar que la solucion funcione correctamente.
Los test son una serie de archivos en formato binario con su correspondiente versi\'on hexadecimal.
Estas salidas fueron realizadas con otro programa que se uso como referencia para desarrollar el presente trabajo (xxd\footnotemark).
\footnotetext{http://linux.about.com/library/cmd/blcmdl1\_xxd.htm}
Los tests tambi\'en pueden ser usados para dar ejemplos de uso de ejecuci\'on del programa.
\subsection{Compilaci\'on}
\paragraph{}
Para compilar el programa se debe escribir en linea de comando lo siguiente:
\newline\verb
gcc tp0.c -o tp0
\paragraph{}
En caso de querer obtener el archivo de assembly de MIPS se debe incluir el parametro -S:
\newline\verb
gcc tp0.c -o tp0.s -S

\subsection{Ejecuci\'on}
\paragraph{}
La ejecuci\'on del programa es por linea de comando.
Se debe abrir una consola en el directorio en el que est\'a ubicado el programa y escribir lo siguiente:
\newline\verb
./tp0 -h
\paragraph{}
Si todo funciona como debe veremos el mensaje de ayuda del programa.
Podemos correrlo tambi\'en con la opcion -V para ver la versi\'on del programa.
\paragraph{}
Si observamos la carpeta test y vemos el contenido del archivo test0.txt\footnotemark veremos que contiene una simple oraci\'on.
\footnotetext{Mediante el comando cat, por ejemplo.}
Tambi\'en se encuentra en ese directorio un archivo test0.out que contiene la salida del programa xxd en hexadecimal.
Para probar el programa podemos realizar el siguiente comando.
\newline\verb
tp0 -i tests/test0.txt -l 16
\paragraph{}
Si todo marcha seg\'un lo esperado la salida del programa (por stout) se parecer\'a bastante al archivo tests/tp0.out.
Podemos realizar pruebas similares con los dem\'as archivos de prueba.

\subsection{Comprobacion}
\paragraph{}
Puede comprobarse la correcta ejecucion del sistema para un determinado archivo mediante las siguientes sentencias:
\begin{verbatim}
$xxd -p archivo_input > output_esperado
./tp0 -l 30 -i archivo_input -o output_actual
$diff output_esperado output_actual

\end{verbatim}
\paragraph{}
En caso de que se haya ejecutado correctamente, el comando diff no retornara ningun resultado. Caso contrario, se listaran las lineas de los archivos resultantes donde ha habido diferencias.
\newpage

\section{Troubleshooting}
\subsection{No se puede ejecutar el programa tp0}
\paragraph{}
Este problema se debe a que el programa no tiene permiso de ejecuci\'on.
Se soluciona dandole permiso al programa:
\newline\verb
chmod +x tp0

\newpage

\section{Ejemplos de ejecucion}

\paragraph{}
Estos son algunos ejemplos de ejecucion de la aplicaci\'on:

\begin{verbatim}

emi@ubuntu:~/Desktop/tp/trunk/tp0$ ./tp0
hola hola hola
686f6c6120686f6c6120686f6c61

emi@ubuntu:~/Desktop/tp/trunk/tp0$ ./tp0 -b
686f6c6120686f6c6120686f6c61
hola hola hola

emi@ubuntu:~/Desktop/tp/trunk/tp0$ ./tp0 -i /dev/random -l 16
bf5afde102562d5e5c6566e3b7966fa7
923cafa2fc93393b0624fdc1262f576c
5c210ee17d4065db18bf8c05d53a19d8
f54b86af717bdfa9860789c8eb91dac2
b57496a7b9080a01a6c8dad13d26c7e2
182e2f8b28fa35819073b9ced05f7e4d
328c01e249631a436ab9c5e344f1f878

emi@ubuntu:~/Desktop/tp/trunk/tp0$      

Con archivos:

$ cat letras2
The quick brown fox jumps over                        
the lazy dogggggggggg                                 
5432878998&^%$%#(*()*%/***()*)(}{L:<{}|
"><>"?"|}{+_)=-][\'/.,'\]][[=-09876
(&*&^%$#@!~~``

$ ./tp0 -i letras2.txt -o ./letrasHex.txt
$ cat letrasHex
54686520717569636b2062726f776e20666f78206a756d7073206f7665720a746865206c617a
7920646f676767676767676767670a35343332383738393938265e25242523282a28292a252f
2a2a2a28292a29287d7b4c3a3c7b7d7c0a223e3c3e223f227c7d7b2b5f293d2d5d5b5c272f2e
2c275c5d5d5b5b3d2d30393837360a28262a265e25242340217e7e60600a

$ ./tp0 -i ./letrasHex.txt -o ./letrasSalida.txt -b
$ cat letrasSalida
The quick brown fox jumps over
the lazy dogggggggggg
5432878998&^%$%#(*()*%/***()*)(}{L:<{}|
"><>"?"|}{+_)=-][\'/.,'\]][[=-09876
(&*&^%$#@!~~``

$ diff -a letras2 letrasSalida
$ diff -q letras2 letrasSalida
$ diff -w letras2 letrasSalida
$ diff -y letras2 letrasSalida
The quick brown fox jumps over                    The quick brown fox jumps over
the lazy dogggggggggg                             the lazy dogggggggggg
5432878998&^%$%#(*()*%/***()*)(}{L:<{}|           5432878998&^%$%#(*()*%/***()*)(}{L:<{}|
"><>"?"|}{+_)=-][\'/.,'\]][[=-09876               "><>"?"|}{+_)=-][\'/.,'\]][[=-09876
(&*&^%$#@!~~``                                    (&*&^%$#@!~~``

$ diff -s letras2 letrasSalida
Los archivos letras2 y letrasSalida son idénticos

\end{verbatim}

\newpage

\section{Apendice 1: Enunciado}

\paragraph{}
A continuacion se incluye el enunciado original del trabajo practico.

\newpage

\section{Apendice 2: Codigo fuente}

\paragraph{}
A continuacion se incluye el codigo fuente de la solucion implementada.
\begin{verbatim}

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define TAMANIO_BUFFER 5

void saveErrors(char* message, char* ref)
{
     FILE* fdErr=fopen("./errores.txt","w");
     fprintf(fdErr,message,ref);
     fclose(fdErr);
     exit(0);
}     

void printValues(char modo, int stdOutput, char* output, int value1, int value2, 
                     int endLine, char letra)
{
     FILE *fdOut;
     
     //si es salida estandar guardamos caracteres en el modo que corresponda
     if(stdOutput==1){
       if(modo=='x'){
         if(endLine==1) printf("%x%x\n",value2,value1);
         else           printf("%x%x",value2,value1);
       }
       else{
         if(endLine==1) printf("%c\n",letra);
         else           printf("%c",letra);
       }          
     }
     else{
       fdOut=fopen(output,"a");
       if(modo=='x'){
	       if(endLine==1) fprintf(fdOut,"%x%x\n",value2,value1);
	       else	          fprintf(fdOut,"%x%x",value2,value1);
       }
       else{
           if(endLine==1) fprintf(fdOut,"%c\n",letra);
           else           fprintf(fdOut,"%c",letra);
       }
       fclose(fdOut);
     }
}

int getIntegerValue(char letra)
{
    int i;
    switch(letra)
    {
       case 'a': i=10;break;
       case 'b': i=11;break;
       case 'c': i=12;break;
       case 'd': i=13;break;
       case 'e': i=14;break;
       case 'f': i=15;break;
       default: break;
    }
    return i;
}

void inverseProcess (unsigned char letra1, unsigned char letra2, int stdOutput, 
                     char* output)
{
   unsigned char letraFinal;
   int letraInt,letraFinalInt,scale,i=0,value1=0,value2=0;
   
   //procesamos la primer letra hexadecimal
   if((letra1=='a')||(letra1=='b')||(letra1=='c')||(letra1=='d')||
      (letra1=='e')||(letra1=='f')){
      letraInt=getIntegerValue(letra1);
      letraInt<<=4;
   }
   else{
      letra1<<=4;
      letraInt=(int)letra1;
   }
   
   //procesamos la segunda letra hexadecimal
   if((letra2=='a')||(letra2=='b')||(letra2=='c')||(letra2=='d')||
      (letra2=='e')||(letra2=='f'))
      value1=getIntegerValue(letra2);
   else{
      for (scale=1; letra2!=0; letra2>>=1){
         if ( letra2 & 1){
            if(i<4) value1+=scale;
            else    value2+=scale;
         }
         i++;
         if(i==4) scale=1;
         else     scale*=2;
      }
   }
   
   //hacemos un OR bit a bit entre las dos partes para formar el caracter 
   //(casteado en Integer) buscado y lo convertimos a char
   letraFinalInt= letraInt | value1;
   letraFinal=(char)letraFinalInt;
   
   //guardamos el char con value1=0, value2=0 y endLine=0 (todos los carateres 
   //de corrido)
   printValues('b',stdOutput,output,0,0,0,letraFinal);
}

void process (unsigned char letra, int stdOutput, char* output, int endLine)
{
      int i=0,scale,value1=0,value2=0;
      for (scale=1; letra!=0; letra>>=1){
          if ( letra & 1){
               if(i<4) value1+=scale;
               else    value2+=scale;
          }
          i++;
          if(i==4) scale=1;
          else     scale*=2;
      }
      
      //guardamos los valores segun los valores new line y stdOut
      //letra=0 ya que no estamos en modo -b
      printValues('x',stdOutput,output,value1,value2,endLine,0);
      
}

void binToHex(int stdInput, char* input, int stdOutput, char* output, 
              int lenght, char* frase)
{
   unsigned char letra;
   int i,count=0,endLine=0;
   FILE *fdOut,*fdIn;
   
   //empezamos a procesar los datos de entrada
   if(stdInput==1)
   { 
       //por cada letra leida del teclado llamamos a process, seteando 
       //el parametro "endLine" segn corresponda
       i=0;
       letra=frase[i];
       while(letra!='\0'){
          count++;
          if(count==lenght){endLine=1; count=0;}
          process(letra,stdOutput,output,endLine);
          i++;
          letra=frase[i];
          if(endLine==1) endLine=0;
       }
   }
   else
   {      
       //leemos desde archivo
       fdIn=fopen(input,"r");
       if (fdIn==NULL)
       	 //indicamos inexistencia del archivo
   	 saveErrors("No se encuentra el archivo de entrada: %s",input);
       
       //en caso de existir el archivo de entrada, creamos y, en caso de que 
       //ya exista, borramos el contenido del archivo salida en caso de 
       //contener caracteres almacenados anteriormente
       fdOut= fopen(output,"w");
       fclose(fdOut);
       
       //empezamos a procesar el archivo
       letra=fgetc(fdIn);
       while(feof(fdIn)==0){
          count++;
          if(count==lenght){endLine=1; count=0;}
          process(letra,stdOutput,output,endLine);
          letra=fgetc(fdIn);
          if(endLine==1) endLine=0;
       }
       fclose(fdIn);
   }
}

void hexToBin(int stdInput, char* input, int stdOutput, char* output, 
              char* frase)
{
   int j=0;
   unsigned char letra1,letra2;
   FILE *fdIn,*fdOut;
   
   if(stdInput==1){
       while(frase[j]!='\0'){
          letra1=frase[j];     j++;
          letra2=frase[j];     j++;
          
          //procesamos ambos caracteres hexadecimales
          inverseProcess(letra1,letra2,stdOutput,output);
      }
   }
   else{
       //leemos desde archivo
       fdIn = fopen(input,"r");
       if (fdIn==NULL)
       	 //indicamos inexistencia del archivo de entrada
   	 saveErrors("No se encuentra el archivo de entrada: %s",input);
   
       //en caso de existir el archivo de entrada, creamos y, en caso de que 
       //ya exista, borramos el contenido del archivo salida en caso de 
       //contener caracteres almacenados anteriormente
       fdOut= fopen(output,"w");
       fclose(fdOut);
       
       //empezamos a procesar el archivo
       letra1=fgetc(fdIn);
       while(feof(fdIn)==0){
          letra2=fgetc(fdIn);
          
          //procesamos ambos caracteres hexadecimales
          inverseProcess(letra1,letra2,stdOutput,output);
          
          //leemos los siguientes valores hexadecimales
          letra1=fgetc(fdIn);
          if(letra1=='\n') letra1=fgetc(fdIn);
       }
       fclose(fdIn);
   }
}

char* leerLinea()
{
   char* acumulador = malloc(TAMANIO_BUFFER);
   char* end;
   char buf[TAMANIO_BUFFER+1];
   int acumuladorSize = TAMANIO_BUFFER+1;
   *acumulador = '\0';

   while ( !feof(stdin) )
   {
     fgets(buf, TAMANIO_BUFFER+1, stdin);
     // fgets agrega un caracter al final de la lectura así que leo 
     // TAMANIO_BUFFER+1. Ver: http://en.wikipedia.org/wiki/Fgets
     strcat(acumulador, buf);
     end = strchr(acumulador, '\n');
     
     if (end == NULL)
     {
     	acumuladorSize += TAMANIO_BUFFER+1;
     	acumulador = realloc(acumulador, acumuladorSize);
     }
     else
     {
     	// fin de linea
     	*end = '\0';
     	break;
     }
   }
   
   return acumulador;
}

int mostrarAyuda()
{
	printf("\
Usage:\n\
  tp0 -h\n\
  tp0 -V\n\
  tp0 [options]\n\
Options:\n\
  -h, --help         Print this information.\n\
  -V, --version      Print version and quit.\n\
  -x, --hexdump      Hexdump mode: encode the input (binary file) in 
                     hexadecimal format (default).\n\
  -b, --binary       Binary mode: decode the input (hexdump file) in binary\n\
                     format.\n\
  -i, --input        Path to input file (defaults to stdin).\n\
  -o, --output       Path to output file (defaults to stdout).\n\
  -l, --length       Number of hex bytes per line (line length) at 
                     the output in hexdump mode (0 = default = no limit).\n\
Examples:\n\
  tp0\n\
  tp0 -i -\n\
  tp0 -i - -o - -x\n\
  tp0 -b\n\
  tp0 -i /dev/random -o /tmp/random-hexdump -l 16\n\
	\n");
	
	return 0;
}

int mostrarVersion()
{
	printf("tp0 V1.0 by Marcelo Suvia, Emiliano Ritiro, Diego Sisto\n");
	
	return 0;
}

int main(int argc, char *argv[])
{
  //opciones por default
  int lenght=0;
  char modo='x';
  int stdInput=1,stdOutput=1;
    
  //seteo de variables de entrada
  char letra;
  char *input,*output,*frase;
  int i;
  
  for(i=1;i<argc;i++)
  {
     if (argv[i][0]=='-' && argv[i][1]!='-')
     { // argumentos con -<letra>, con <letra> distinto de -
         letra=argv[i][1];
         switch(letra)
         {
            case 'i': if((i+1<argc)&&(argv[i+1][0]!= '-'))
                      { input=argv[i+1]; stdInput=0;}
                      break;
            case 'o': if((i+1<argc)&&(argv[i+1][0]!= '-'))
                      { output=argv[i+1]; stdOutput=0;}
                      break;
            case 'l': if((i+1<argc)&&(argv[i+1][0]!= '-')) 
                        lenght=atoi(argv[i+1]);
                      break;
            case 'b': modo='b';
                      break;
            case 'h': modo='h';
            		  break;
            case 'V': modo='v';
            		  break;
            default : saveErrors("Parametro invalido: %s\n",argv[i]);
         }
         //si es una parametro del tipo -<letra> verificamos que no 
         //contenga mas nada
         if(strlen(argv[i])> 2)
            saveErrors("Parametro invalido: %s\n",argv[i]);
     }
     
     if (strcmp(argv[i], "--help")==0)
     {
     	modo='h';
     }
     
     if (strcmp(argv[i], "--version")==0)
     {
     	modo='v';
     }
     
     if (strcmp(argv[i], "--binary")==0)
     {
     	modo='b';
     }
     
     if (strcmp(argv[i], "--input")==0)
     {
     	if((i+1<argc)&&(argv[i+1][0]!= '-')){ input=argv[i+1]; stdInput=0;}
     }
     
     if (strcmp(argv[i], "--output")==0)
     {
     	if((i+1<argc)&&(argv[i+1][0]!= '-')){ output=argv[i+1]; stdOutput=0;}
     }
     
     if (strcmp(argv[i], "--length")==0)
     {
     	if((i+1<argc)&&(argv[i+1][0]!= '-')) lenght=atoi(argv[i+1]);
     }
  }
  
  // veo si es el modo de ayuda
  if (modo == 'h')
  {
  	 mostrarAyuda();
  	 return 0;
  }
  
  // veo si es el modo de version
  if (modo == 'v')
  {
  	 mostrarVersion();
  	 return 0;
  }
  
  //obtenemos la frase a convertir en caso de que sea entrada por teclado
  if(stdInput==1)
     frase = leerLinea();
    
  //generamos el archivo segun los requerimientos
  if(modo=='x') binToHex(stdInput,input,stdOutput,output,lenght,frase);
  else          hexToBin(stdInput,input,stdOutput,output,frase);
  
  return 0;
}


\end{verbatim}
\end{document}